(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        const $ = require("jquery");
        module.exports = factory($)
    } else {
        root.Ani = factory(root.$)
    }
}(this, function ($) {
    let DEFAULT_OPTIONS = {
        runtime: {
            preload: function () {

            },
            create: function () {

            },
            update: function () {

            },
            render: function () {

            }
        }
    };
    let Ani: {};

    class Sprite {
        public left: any;
        public top: any;
        public width: any;
        public height: any;
        public visible: any;
        public image: any;

        constructor(arg) {
            this.left = arg.left || 0;
            this.top = arg.top || 0;
            this.width = arg.width || 10;
            this.height = arg.height || 10;
            this.visible = true;
            this.image = arg.image
        }

        public paint(context) {
            context.save();
            context.drawImage(this.image, 0, 0, this.image.width, this.image.height,
                this.left, this.top, this.width, this.height);
            context.restore()
        }
    }

    class Game {
        private canvasInstance: any;
        private canvasContext: any;
        private options: any;
        private spritesArr: any;

        constructor(canvasW = 100, canvasH = 100, Flag = 'body', runtime) {
            this.options = {
                canvasW,
                canvasH,
                Flag,
                ...DEFAULT_OPTIONS.runtime,
                ...runtime
            };
            this.spritesArr = [];
            this.runtimeRun();
        }

        private async runtimeRun() {
            try {
                this.options.preload.call(this);
                await this.createCanvas();
                this.options.create.call(this, this.canvasContext);
                this.core.draw();
            } catch (e) {
                console.log(e)
            }
        }

        private async createCanvas() {
            try {
                this.canvasInstance = document.querySelector(this.options.Flag);
                this.canvasInstance.width = this.options.canvasW;
                this.canvasInstance.height = this.options.canvasH;
                this.canvasContext = this.canvasInstance.getContext("2d")
            } catch (e) {
                console.log(e)
            }
        }

        public add = (() => {
            return {
                model: (posX, posY, Obj) => {
                    let ctx = this.canvasContext,
                        moveItem = null,
                        startPos = {x: 0, y: 0},
                        moving = false,
                        canvas = $(this.canvasInstance);

                    var rectList = [[50, 50, 50, 50], [120, 120, 80, 60], [30, 150, 60, 80]];
                    var drawRect = function (x, y, w, h) {
                        ctx.beginPath();
                        ctx.rect(x, y, w, h);
                    };
                    var getCanvasPoint = (x, y) => {
                        var canvasOffset = $(this.canvasInstance).offset();
                        return {
                            x: x - canvasOffset.left,
                            y: y - canvasOffset.top
                        }
                    };

                    ctx.clearRect(0, 0, this.canvasInstance.width, this.canvasInstance.height);
                    $.each(rectList, (index, arr) => {
                        drawRect(rectList[index][0], rectList[index][1], rectList[index][2], rectList[index][3]);
                        ctx.stroke();
                    });
                    canvas.on("mousedown", (e) => {
                        moving = true;
                        var point = getCanvasPoint(e.pageX, e.pageY);
                        $.each(rectList, function (n, v) {
                            drawRect(rectList[n][0], rectList[n][1], rectList[n][2], rectList[n][3]);
                            if (ctx.isPointInPath(point.x, point.y)) {
                                moveItem = n;
                                startPos.x = point.x;
                                startPos.y = point.y;
                                ctx.strokeStyle = "#ff4444";
                            } else {
                                ctx.strokeStyle = "#000";
                            }
                            ctx.stroke();
                        });
                        this.options.update.call(this, this.canvasContext);
                    });
                    canvas.on("mousemove", (e) => {
                        if (!moving && moveItem == null) {
                            return;
                        }
                        ctx.clearRect(0, 0, canvas.width(), canvas.height());
                        var point = getCanvasPoint(e.pageX, e.pageY);
                        $.each(rectList, function (n, v) {
                            var moveX = 0,
                                moveY = 0;

                            if (n !== moveItem) {
                                ctx.strokeStyle = "#000";
                            } else {
                                moveX = point.x - startPos.x;
                                moveY = point.y - startPos.y;

                                ctx.strokeStyle = "#ff4444";
                            }
                            drawRect(rectList[n][0] + moveX, rectList[n][1] + moveY, rectList[n][2], rectList[n][3]);
                            ctx.stroke();
                        });
                        this.options.update.call(this, this.canvasContext);
                    });
                    canvas.on("mouseup", function (e) {
                        moving = false;
                        $.each(rectList, function (n) {
                            if (n == moveItem) {
                                var point = getCanvasPoint(e.pageX, e.pageY);
                                rectList[n][0] += point.x - startPos.x;
                                rectList[n][1] += point.y - startPos.y;
                            }
                        });
                        startPos = {x: 0, y: 0};
                        moveItem = null
                    });
                },
                rect: (rectArr) => {
                    this.spritesArr.push({
                        data: rectArr,
                    })
                },
            }
        }).bind(this)();
        //核心方法
        public core = (() => {
            return {
                draw: () => {
                    $.each(this.spritesArr, (index, item) => {
                        this.methods.drawRect(this.canvasContext, item.data[0], item.data[1], item.data[2], item.data[3])
                    });
                    this.methods.drawGrid(this.canvasContext, 'lightgray', 10, 10);
                },
                bindEvent: () => {

                },
                update: () => {

                }
            }
        }).bind(this)();

        public methods = (() => {
            return {
                drawGrid(ctx, color, stepx, stepy) {
                    ctx.strokeStyle = color;
                    ctx.lineWidth = 0.5;


                    for (var i = stepx + 0.5; i < ctx.canvas.width; i += stepx) {
                        ctx.beginPath();
                        ctx.moveTo(i, 0);
                        ctx.lineTo(i, ctx.canvas.height);
                        ctx.stroke();
                    }

                    for (var i = stepy + 0.5; i < ctx.canvas.height; i += stepy) {
                        ctx.beginPath();
                        ctx.moveTo(0, i);
                        ctx.lineTo(ctx.canvas.width, i);
                        ctx.stroke();
                    }
                },
                drawRect(ctx, x, y, w, h) {
                    ctx.beginPath();
                    ctx.rect(x, y, w, h);
                    ctx.stroke()
                }
            }
        }).bind(this)();
    }

    Ani = {
        Game
    };
    return Ani
}));


